package de.ralf.urwalking.soplugin;

import java.util.Locale;

/**
 * This class is used to build a correct query for the database to get all salient objects within a sector of a circle
 * around the user/ device
 * 
 * @author Florian Ludwig
 * @author Andreas Rauscher
 * @version 1.0 - September 30, 2013.
 */
public class SOQueryBuilder {

	/**
	 * a pre-defined radius which is used to get all salient objects within a circle with this radius in meters
	 */
	private static final double RADIUS = 32;

	/** defines the table from where to get the values and furthermore defines which values are needed */
	private String SELECTION = "SELECT uniqueid, name, x, y, refpoi, refgebid, refindoor "
			+ "FROM urw_urw_salient_object AS obj ";
	/** represents the condition of the query */
	private String condition = "WHERE ST_Contains(%s, obj.geom_point);";
	/** represents the circle */
	private String circle = "ST_Buffer(ST_SetSRID(ST_MakePoint(%f, %f),31468), %f)";
	/** represents the triangle */
	private String triangle = "ST_Rotate(ST_MakePolygon(ST_GeomFromText('LINESTRING(%f %f, %f %f, %f %f, %f %f)',"
			+ "31468)), %f, ST_SetSRID(ST_MakePoint(%f, %f),31468))";

	/** viewing direction of the user derived by the azimuth angle of the device */
	private float userDirection;
	/** location of the user derived by the location of the device within the EPSG system */
	private EPSGPoint userLocation;

	/**
	 * Constructor to create a new SOQueryBuilder-Object.
	 * 
	 * @param viewingDirection
	 *            viewing direction (Azimuth of the device)
	 * @param userPosX
	 *            x-position of the device
	 * @param userPosY
	 *            y-position of the device
	 */
	public SOQueryBuilder(float viewingDirection, double userPosX, double userPosY) {

		// Well this is awkward. Looks like we have to correct the direction though it should already be in radians and
		// counterclockwise. 
		userDirection = -(viewingDirection + (float) Math.PI / 2);
		userLocation = new EPSGPoint(userPosX, userPosY);
	}

	/**
	 * Method which creates and then returns the query for the database.
	 * 
	 * @return query
	 */
	public String buildQuery() {
		String query = "";

		EPSGPoint[] mPoints = calcPoints(userLocation);
		double x = mPoints[2].getX();
		double x1 = mPoints[0].getX();
		double x2 = mPoints[1].getX();
		double y = mPoints[2].getY();
		double y1 = mPoints[0].getY();
		double y2 = mPoints[1].getY();

		circle = String.format(Locale.US, circle, x, y, RADIUS);
		triangle = String.format(Locale.US, triangle, x, y, x1, y1, x2, y2, x, y, userDirection, x, y);
		String intersection = "ST_Intersection(" + circle + ", " + triangle + ")";
		condition = String.format(Locale.US, condition, intersection);
		query = SELECTION + condition;

		return query;
	}

	/**
	 * Calculates the missing two points for the needed triangle and return an array which includes these two points and
	 * the position of the device on earth.
	 * 
	 * @param userLocation
	 * 
	 * @return EPSG[] which includes the position of the device and the two calculated points for the sector
	 */
	public static EPSGPoint[] calcPoints(EPSGPoint userLocation) {

		double x = userLocation.getX();
		double y = userLocation.getY();

		EPSGPoint[] points = new EPSGPoint[3];
		points[0] = new EPSGPoint();
		points[1] = new EPSGPoint();
		points[2] = new EPSGPoint();

		double dif = RADIUS * Math.tan(32.0);

		double xB = x + dif;
		double yB = y + RADIUS;
		double xC = x - dif;
		double yC = y + RADIUS;

		points[0].setX(xB);
		points[0].setY(yB);
		points[1].setX(xC);
		points[1].setY(yC);
		points[2].setX(x);
		points[2].setY(y);

		return points;
	}

}
